IDENTIFY MACRO-AREAS OR MARKET FIELDS within the database to acquire
some general awareness on its content
library(tidyverse)
data <- read_csv("../../data/data_subset1.csv")
names(data)
library(skimr)
#skim(data)
Wordcloud
Codice da: Using
tidytext to make word clouds (richpauloo.github.io)
library(dplyr) # for data wrangling
library(tidytext) # for NLP
library(stringr) # to deal with strings
library(wordcloud) # to render wordclouds
library(knitr) # for tables
library(DT) # for dynamic tables
library(tidyr)
tidy_dat <- tidyr::gather(data %>%
unite(col="united", abstract, title, sep=" ") %>%
select(united), key, word) %>% select(word)
tidy_dat
library(SnowballC)
#uso lo stemming perchè il lemming (udpipe_annotate) sarebbe troppo lento ad eseguire
tokens <- tidy_dat %>%
unnest_tokens(word, word) %>%
mutate(word = wordStem(word)) %>%
dplyr::count(word, sort = TRUE) %>%
ungroup()
data("stop_words")
tokens_clean <- tokens %>%
anti_join(stop_words)
nums <- tokens_clean %>% filter(str_detect(word, "^[0-9]")) %>% select(word) %>% unique()
tokens_clean <- tokens_clean %>%
anti_join(nums, by = "word")
tokens_clean %>% head(100)
pal <- brewer.pal(8,"Dark2")
tokens_clean %>%
with(wordcloud(word, n, random.order = FALSE, max.words = 50, colors=pal))
uni_sw <- data.frame(word = c("claim", "based", "model",
"data", "invetion", "network",
"methods", "dataset",
"l3", "computer", "computing",
"device", "plurality",
"comprising", "word",
"user",
"based",
"comprises",
"system",
"image",
"model",
"processor",
"process",
"sentence",
"workload",
"method",
"data",
"system"
))
tokens_clean <- tokens_clean %>%
anti_join(uni_sw, by = "word")
pal <- brewer.pal(8,"Dark2")
tokens_clean %>%
with(wordcloud(word, n, random.order = FALSE, max.words = 50, colors=pal))
Topic modeling
Codice da: Topic modeling
| Text Mining with R (tidytextmining.com)
library(topicmodels)
data %>%
group_by(filename)
data_word_count = data %>%
select(filename, abstract, claims, title) %>%
unite(col="united", abstract, title, sep=" ") %>%
unnest_tokens(word, united) %>%
mutate(word = wordStem(word)) %>%
count(filename, word, sort = TRUE) %>%
anti_join(stop_words)
data_word_count %>% head(10)
data_dtm <- data_word_count %>%
cast_dtm(filename, word, n)
data_dtm
data_lda <- LDA(data_dtm, k = 16, control = list(seed = 1234))
library(reshape2)
ap_topics <- tidy(data_lda, matrix = "beta")
ap_topics
ap_top_terms <- ap_topics %>%
group_by(topic) %>%
slice_max(beta, n = 7) %>%
ungroup() %>%
arrange(topic, -beta)
ap_gg = ap_top_terms %>%
mutate(term = reorder_within(term, beta, topic)) %>%
ggplot(aes(beta, term, fill = factor(topic))) +
geom_col(show.legend = FALSE) +
facet_wrap(~ topic, scales = "free") +
scale_y_reordered()
ap_gg
beta_wide <- ap_topics %>%
mutate(topic = paste0("topic", topic)) %>%
pivot_wider(names_from = topic, values_from = beta) %>%
filter(topic1 > .001 | topic2 > .001) %>%
mutate(log_ratio = log2(topic2 / topic1))
beta_wide
Bigrams
codice da Relationships between
words: n-grams and correlations | Text Mining with R
(tidytextmining.com)
bigrams <- data %>%
unite(col="united", title, sep=" ") %>%
unnest_tokens(bigram, united, token = "ngrams", n = 2) %>%
select(bigram) #%>%
#count(bigram, sort=TRUE)
bigrams
bigrams_separated <- bigrams %>%
separate(bigram, c("word1", "word2"), sep = " ")
bigrams_filtered <- bigrams_separated %>%
filter(!word1 %in% stop_words$word) %>%
filter(!word2 %in% stop_words$word) %>%
filter(!str_detect(word1, "^[0-9]")) %>%
filter(!str_detect(word2, "^[0-9]"))
# new bigram counts:
bigram_counts <- bigrams_filtered %>%
mutate(word1 = wordStem(word1)) %>%
mutate(word2 = wordStem(word2)) %>%
count(word1, word2, sort = TRUE)
bigram_counts
library(igraph)
library(ggraph)
bigram_graph <- bigram_counts %>%
filter(n >= 500) %>%
graph_from_data_frame()
set.seed(2017)
gg <- ggraph(bigram_graph, layout = "fr") + #fr o graphopt
geom_edge_link() +
geom_node_point() +
geom_node_text(aes(label = name), hjust = 1, vjust=1) +
theme_void()
gg
library(igraph)
library(ggiraph)
gg
Using CPC
codice sunburst da: Create
Basic Sunburst Graphs with ggplot2 | by Yahia El Gamal | Optima . Blog |
Medium
library(tidyverse)
cpc_descr <- read_csv("../../data/CPC_descriptions.csv")
Rows: 259657 Columns: 8
-- Column specification ----------------------------------------------
Delimiter: ","
chr (8): code_1, code_3, code_4, code_full, descr_1, descr_3, desc...
i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
cpc_descr %>% head(5)
data %>% head(5)
data %>% mutate(tmp = substr(ipc_classes[1], 0, 3))
data %>%
mutate(code_4 = tolower(substr(ipc_classes, 0, 4))) %>%
inner_join(cpc_descr
%>% select(code_4, descr_1, descr_3, descr_4) %>%
distinct(),
by="code_4"
) -> res
res %>% head()
res <- res %>%
select(filename, descr_1, descr_3, descr_4) %>%
count(filename, descr_1, descr_3, descr_4, sort = TRUE)
res
library(sunburstR)
res$descr_1<-gsub("-","_",as.character(res$descr_1))
res$descr_3<-gsub("-","_",as.character(res$descr_3))
res$descr_4<-gsub("-","_",as.character(res$descr_4))
dat <- res %>%
unite(col="united", descr_1, descr_3, descr_4, sep="-") %>%
group_by(united) %>%
count(sort= TRUE)
dat %>% head()
library(d3r)
sb3 <- sund2b(dat,
breadcrumbs = sund2bBreadcrumb(enabled = TRUE),
showLabels=TRUE)
sb3
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpJREVOVElGWSBNQUNSTy1BUkVBUyBPUiBNQVJLRVQgRklFTERTIHdpdGhpbiB0aGUgZGF0YWJhc2UgdG8gYWNxdWlyZSBzb21lIGdlbmVyYWwgYXdhcmVuZXNzIG9uIGl0cyBjb250ZW50DQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCmRhdGEgPC0gcmVhZF9jc3YoIi4uLy4uL2RhdGEvZGF0YV9zdWJzZXQxLmNzdiIpDQoNCm5hbWVzKGRhdGEpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHNraW1yKQ0KI3NraW0oZGF0YSkNCmBgYA0KDQojIyBXb3JkY2xvdWQNCg0KQ29kaWNlIGRhOiBbVXNpbmcgdGlkeXRleHQgdG8gbWFrZSB3b3JkIGNsb3VkcyAocmljaHBhdWxvby5naXRodWIuaW8pXShodHRwczovL3JpY2hwYXVsb28uZ2l0aHViLmlvLzIwMTctMTItMjktVXNpbmctdGlkeXRleHQtdG8tbWFrZS13b3JkLWNsb3Vkcy8pDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikgIyBmb3IgZGF0YSB3cmFuZ2xpbmcNCmxpYnJhcnkodGlkeXRleHQpICMgZm9yIE5MUA0KbGlicmFyeShzdHJpbmdyKSAjIHRvIGRlYWwgd2l0aCBzdHJpbmdzDQpsaWJyYXJ5KHdvcmRjbG91ZCkgIyB0byByZW5kZXIgd29yZGNsb3Vkcw0KbGlicmFyeShrbml0cikgIyBmb3IgdGFibGVzDQpsaWJyYXJ5KERUKSAjIGZvciBkeW5hbWljIHRhYmxlcw0KbGlicmFyeSh0aWR5cikNCg0KdGlkeV9kYXQgPC0gdGlkeXI6OmdhdGhlcihkYXRhICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXRlKGNvbD0idW5pdGVkIiwgYWJzdHJhY3QsIHRpdGxlLCBzZXA9IiAiKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QodW5pdGVkKSwga2V5LCB3b3JkKSAlPiUgc2VsZWN0KHdvcmQpDQoNCnRpZHlfZGF0DQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoU25vd2JhbGxDKQ0KDQojdXNvIGxvIHN0ZW1taW5nIHBlcmNow6ggaWwgbGVtbWluZyAodWRwaXBlX2Fubm90YXRlKSBzYXJlYmJlIHRyb3BwbyBsZW50byBhZCBlc2VndWlyZQ0KdG9rZW5zIDwtIHRpZHlfZGF0ICU+JSANCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB3b3JkKSAlPiUgDQogIG11dGF0ZSh3b3JkID0gd29yZFN0ZW0od29yZCkpICU+JSANCiAgZHBseXI6OmNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQpkYXRhKCJzdG9wX3dvcmRzIikNCnRva2Vuc19jbGVhbiA8LSB0b2tlbnMgJT4lDQogIGFudGlfam9pbihzdG9wX3dvcmRzKQ0KDQpudW1zIDwtIHRva2Vuc19jbGVhbiAlPiUgZmlsdGVyKHN0cl9kZXRlY3Qod29yZCwgIl5bMC05XSIpKSAlPiUgc2VsZWN0KHdvcmQpICU+JSB1bmlxdWUoKQ0KDQp0b2tlbnNfY2xlYW4gPC0gdG9rZW5zX2NsZWFuICU+JSANCiAgYW50aV9qb2luKG51bXMsIGJ5ID0gIndvcmQiKQ0KDQp0b2tlbnNfY2xlYW4gJT4lIGhlYWQoMTAwKQ0KDQpgYGANCg0KYGBge3J9DQpwYWwgPC0gYnJld2VyLnBhbCg4LCJEYXJrMiIpDQoNCnRva2Vuc19jbGVhbiAlPiUgDQogIHdpdGgod29yZGNsb3VkKHdvcmQsIG4sIHJhbmRvbS5vcmRlciA9IEZBTFNFLCBtYXgud29yZHMgPSA1MCwgY29sb3JzPXBhbCkpDQpgYGANCg0KYGBge3J9DQp1bmlfc3cgPC0gZGF0YS5mcmFtZSh3b3JkID0gYygiY2xhaW0iLCAiYmFzZWQiLCAibW9kZWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRhdGEiLCAiaW52ZXRpb24iLCAibmV0d29yayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWV0aG9kcyIsICJkYXRhc2V0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJsMyIsICJjb21wdXRlciIsICJjb21wdXRpbmciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRldmljZSIsICJwbHVyYWxpdHkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbXByaXNpbmciLCAid29yZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidXNlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbXByaXNlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic3lzdGVtIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJpbWFnZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibW9kZWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInByb2Nlc3NvciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHJvY2VzcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2VudGVuY2UiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndvcmtsb2FkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtZXRob2QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRhdGEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInN5c3RlbSINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpDQoNCnRva2Vuc19jbGVhbiA8LSB0b2tlbnNfY2xlYW4gJT4lIA0KICBhbnRpX2pvaW4odW5pX3N3LCBieSA9ICJ3b3JkIikNCg0KYGBgDQoNCmBgYHtyfQ0KcGFsIDwtIGJyZXdlci5wYWwoOCwiRGFyazIiKQ0KDQp0b2tlbnNfY2xlYW4gJT4lIA0KICB3aXRoKHdvcmRjbG91ZCh3b3JkLCBuLCByYW5kb20ub3JkZXIgPSBGQUxTRSwgbWF4LndvcmRzID0gNTAsIGNvbG9ycz1wYWwpKQ0KDQoNCmBgYA0KDQojIyBUb3BpYyBtb2RlbGluZw0KDQpDb2RpY2UgZGE6IFtUb3BpYyBtb2RlbGluZyBcfCBUZXh0IE1pbmluZyB3aXRoIFIgKHRpZHl0ZXh0bWluaW5nLmNvbSldKGh0dHBzOi8vd3d3LnRpZHl0ZXh0bWluaW5nLmNvbS90b3BpY21vZGVsaW5nLmh0bWwpDQoNCmBgYHtyfQ0KbGlicmFyeSh0b3BpY21vZGVscykNCmBgYA0KDQpgYGB7cn0NCmRhdGEgJT4lDQogIGdyb3VwX2J5KGZpbGVuYW1lKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YV93b3JkX2NvdW50ID0gZGF0YSAlPiUNCiAgc2VsZWN0KGZpbGVuYW1lLCBhYnN0cmFjdCwgY2xhaW1zLCB0aXRsZSkgJT4lDQogIHVuaXRlKGNvbD0idW5pdGVkIiwgYWJzdHJhY3QsIHRpdGxlLCBzZXA9IiAiKSAlPiUNCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB1bml0ZWQpICU+JQ0KICBtdXRhdGUod29yZCA9IHdvcmRTdGVtKHdvcmQpKSAlPiUgDQogIGNvdW50KGZpbGVuYW1lLCB3b3JkLCBzb3J0ID0gVFJVRSkgJT4lDQogIGFudGlfam9pbihzdG9wX3dvcmRzKQ0KDQpkYXRhX3dvcmRfY291bnQgJT4lIGhlYWQoMTApDQpgYGANCg0KYGBge3J9DQpkYXRhX2R0bSA8LSBkYXRhX3dvcmRfY291bnQgJT4lDQogIGNhc3RfZHRtKGZpbGVuYW1lLCB3b3JkLCBuKQ0KDQpkYXRhX2R0bQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9sZGEgPC0gTERBKGRhdGFfZHRtLCBrID0gMTYsIGNvbnRyb2wgPSBsaXN0KHNlZWQgPSAxMjM0KSkNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkocmVzaGFwZTIpDQoNCmFwX3RvcGljcyA8LSB0aWR5KGRhdGFfbGRhLCBtYXRyaXggPSAiYmV0YSIpDQoNCmFwX3RvcGljcw0KYGBgDQoNCmBgYHtyfQ0KYXBfdG9wX3Rlcm1zIDwtIGFwX3RvcGljcyAlPiUNCiAgZ3JvdXBfYnkodG9waWMpICU+JQ0KICBzbGljZV9tYXgoYmV0YSwgbiA9IDcpICU+JSANCiAgdW5ncm91cCgpICU+JQ0KICBhcnJhbmdlKHRvcGljLCAtYmV0YSkNCg0KYXBfZ2cgPSBhcF90b3BfdGVybXMgJT4lDQogIG11dGF0ZSh0ZXJtID0gcmVvcmRlcl93aXRoaW4odGVybSwgYmV0YSwgdG9waWMpKSAlPiUNCiAgZ2dwbG90KGFlcyhiZXRhLCB0ZXJtLCBmaWxsID0gZmFjdG9yKHRvcGljKSkpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBmYWNldF93cmFwKH4gdG9waWMsIHNjYWxlcyA9ICJmcmVlIikgKw0KICBzY2FsZV95X3Jlb3JkZXJlZCgpDQoNCg0KYXBfZ2cNCg0KYGBgDQoNClwNCg0KYGBge3J9DQpiZXRhX3dpZGUgPC0gYXBfdG9waWNzICU+JQ0KICBtdXRhdGUodG9waWMgPSBwYXN0ZTAoInRvcGljIiwgdG9waWMpKSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHRvcGljLCB2YWx1ZXNfZnJvbSA9IGJldGEpICU+JSANCiAgZmlsdGVyKHRvcGljMSA+IC4wMDEgfCB0b3BpYzIgPiAuMDAxKSAlPiUNCiAgbXV0YXRlKGxvZ19yYXRpbyA9IGxvZzIodG9waWMyIC8gdG9waWMxKSkNCg0KYmV0YV93aWRlDQpgYGANCg0KIyMgQmlncmFtcw0KDQpjb2RpY2UgZGEgW1JlbGF0aW9uc2hpcHMgYmV0d2VlbiB3b3Jkczogbi1ncmFtcyBhbmQgY29ycmVsYXRpb25zIFx8IFRleHQgTWluaW5nIHdpdGggUiAodGlkeXRleHRtaW5pbmcuY29tKV0oaHR0cHM6Ly93d3cudGlkeXRleHRtaW5pbmcuY29tL25ncmFtcy5odG1sKQ0KDQpgYGB7cn0NCmJpZ3JhbXMgPC0gZGF0YSAlPiUNCiAgdW5pdGUoY29sPSJ1bml0ZWQiLCB0aXRsZSwgc2VwPSIgIikgJT4lDQogIHVubmVzdF90b2tlbnMoYmlncmFtLCB1bml0ZWQsIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUNCiAgc2VsZWN0KGJpZ3JhbSkgIyU+JQ0KICAjY291bnQoYmlncmFtLCBzb3J0PVRSVUUpDQoNCmJpZ3JhbXMNCmBgYA0KDQpgYGB7cn0NCmJpZ3JhbXNfc2VwYXJhdGVkIDwtIGJpZ3JhbXMgJT4lDQogIHNlcGFyYXRlKGJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiKQ0KDQpiaWdyYW1zX2ZpbHRlcmVkIDwtIGJpZ3JhbXNfc2VwYXJhdGVkICU+JQ0KICBmaWx0ZXIoIXdvcmQxICVpbiUgc3RvcF93b3JkcyR3b3JkKSAlPiUNCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHN0b3Bfd29yZHMkd29yZCkgJT4lDQogIGZpbHRlcighc3RyX2RldGVjdCh3b3JkMSwgIl5bMC05XSIpKSAlPiUNCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHdvcmQyLCAiXlswLTldIikpDQoNCiMgbmV3IGJpZ3JhbSBjb3VudHM6DQpiaWdyYW1fY291bnRzIDwtIGJpZ3JhbXNfZmlsdGVyZWQgJT4lIA0KICBtdXRhdGUod29yZDEgPSB3b3JkU3RlbSh3b3JkMSkpICU+JSANCiAgbXV0YXRlKHdvcmQyID0gd29yZFN0ZW0od29yZDIpKSAlPiUgDQogIGNvdW50KHdvcmQxLCB3b3JkMiwgc29ydCA9IFRSVUUpDQoNCmJpZ3JhbV9jb3VudHMNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoaWdyYXBoKQ0KbGlicmFyeShnZ3JhcGgpDQoNCmJpZ3JhbV9ncmFwaCA8LSBiaWdyYW1fY291bnRzICU+JQ0KICBmaWx0ZXIobiA+PSA1MDApICU+JQ0KICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKQ0KDQpzZXQuc2VlZCgyMDE3KQ0KDQpnZyA8LSBnZ3JhcGgoYmlncmFtX2dyYXBoLCBsYXlvdXQgPSAiZnIiKSArICNmciBvIGdyYXBob3B0DQogIGdlb21fZWRnZV9saW5rKCkgKw0KICBnZW9tX25vZGVfcG9pbnQoKSArDQogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCAgaGp1c3QgPSAxLCB2anVzdD0xKSArDQogIHRoZW1lX3ZvaWQoKQ0KDQpnZw0KYGBgDQoNCmBgYHtyfQ0KDQpsaWJyYXJ5KGlncmFwaCkNCmxpYnJhcnkoZ2dpcmFwaCkNCg0KZ2cNCmBgYA0KDQojIyMgVXNpbmcgQ1BDDQoNCmNvZGljZSBzdW5idXJzdCBkYTogW0NyZWF0ZSBCYXNpYyBTdW5idXJzdCBHcmFwaHMgd2l0aCBnZ3Bsb3QyIFx8IGJ5IFlhaGlhIEVsIEdhbWFsIFx8IE9wdGltYSAuIEJsb2cgXHwgTWVkaXVtXShodHRwczovL21lZGl1bS5jb20vb3B0aW1hLWJsb2cvY3JlYXRlLWJhc2ljLXN1bmJ1cnN0LWdyYXBocy13aXRoLWdncGxvdDItN2Q3NDg0ZDkyYzYxKQ0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQpjcGNfZGVzY3IgPC0gcmVhZF9jc3YoIi4uLy4uL2RhdGEvQ1BDX2Rlc2NyaXB0aW9ucy5jc3YiKQ0KDQpjcGNfZGVzY3IgJT4lIGhlYWQoNSkNCmBgYA0KDQpgYGB7cn0NCmRhdGEgJT4lIGhlYWQoNSkNCmBgYA0KDQpgYGB7cn0NCmRhdGEgJT4lIG11dGF0ZSh0bXAgPSBzdWJzdHIoaXBjX2NsYXNzZXNbMV0sIDAsIDMpKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YSAlPiUgDQogIG11dGF0ZShjb2RlXzQgPSB0b2xvd2VyKHN1YnN0cihpcGNfY2xhc3NlcywgMCwgNCkpKSAlPiUNCiAgaW5uZXJfam9pbihjcGNfZGVzY3IgDQogICAgICAgICAgICAgJT4lIHNlbGVjdChjb2RlXzQsIGRlc2NyXzEsIGRlc2NyXzMsIGRlc2NyXzQpICU+JSANCiAgICAgICAgICAgICAgICBkaXN0aW5jdCgpLA0KICAgICAgICAgICAgIGJ5PSJjb2RlXzQiDQogICAgICAgICAgICAgKSAtPiByZXMNCg0KcmVzICU+JSBoZWFkKCkNCmBgYA0KDQpgYGB7cn0NCnJlcyA8LSByZXMgJT4lDQogIHNlbGVjdChmaWxlbmFtZSwgZGVzY3JfMSwgZGVzY3JfMywgZGVzY3JfNCkgJT4lDQogIGNvdW50KGZpbGVuYW1lLCBkZXNjcl8xLCBkZXNjcl8zLCBkZXNjcl80LCBzb3J0ID0gVFJVRSkNCg0KcmVzDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHN1bmJ1cnN0UikNCnJlcyRkZXNjcl8xPC1nc3ViKCItIiwiXyIsYXMuY2hhcmFjdGVyKHJlcyRkZXNjcl8xKSkNCnJlcyRkZXNjcl8zPC1nc3ViKCItIiwiXyIsYXMuY2hhcmFjdGVyKHJlcyRkZXNjcl8zKSkNCnJlcyRkZXNjcl80PC1nc3ViKCItIiwiXyIsYXMuY2hhcmFjdGVyKHJlcyRkZXNjcl80KSkNCg0KZGF0IDwtIHJlcyAlPiUgDQogIHVuaXRlKGNvbD0idW5pdGVkIiwgZGVzY3JfMSwgZGVzY3JfMywgZGVzY3JfNCwgc2VwPSItIikgJT4lDQogIGdyb3VwX2J5KHVuaXRlZCkgJT4lDQogIGNvdW50KHNvcnQ9IFRSVUUpDQoNCmRhdCAlPiUgaGVhZCgpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGQzcikNCiAgDQoNCnNiMyA8LSBzdW5kMmIoZGF0LA0KICAgICAgICAgICAgICBicmVhZGNydW1icyA9IHN1bmQyYkJyZWFkY3J1bWIoZW5hYmxlZCA9IFRSVUUpLCANCiAgICAgICAgICAgICAgc2hvd0xhYmVscz1UUlVFKQ0KDQpzYjMNCmBgYA0K